home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 09 - 1993 / 09.09 Sep 93 / Programmer's Challenge / TileStackWindows.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-22  |  8.0 KB  |  332 lines  |  [TEXT/KAHL]

  1. /*****************************************************
  2.  * TileStackWindows.c
  3.  *
  4.  * Set of routines to quickly rearrange windows
  5.  * on multiple devices.
  6.  *
  7.  * Mike Scanlin  10 July 1993
  8.  ****************************************************/
  9.  
  10. #include <GestaltEqu.h>
  11. #include <Traps.h>
  12. #include "TileStackWindows.h"
  13.  
  14. /*****************************************************
  15.  * defines
  16.  ****************************************************/
  17.  
  18. #define BAD_DEVICE        ((GDHandle) -1)
  19. #define TOPLEFT_SLOP    2
  20. #define BOTRIGHT_SLOP    3
  21. #define NIL                0L
  22.  
  23. /* MAX_WINDOWS is not a real limit but stack space
  24.  * requirements for TileStackWindows are equal to
  25.  * (sizeof(WindowElement) * 2 * MAX_WINDOWS) so
  26.  * don't make it too big. It's the max number of
  27.  * windows that TileStackWindows can deal with.
  28.  */
  29. #define MAX_WINDOWS        100
  30.  
  31. /*****************************************************
  32.  * typedefs
  33.  ****************************************************/
  34.  
  35. typedef pascal long    (**WDefProcHndl)(int var,
  36.     WindowPtr w, int message, long param);
  37.  
  38. /*****************************************************
  39.  * prototypes
  40.  ****************************************************/
  41.  
  42. static GDHandle DominantDevice(Rect *theRect);
  43.  
  44. /*****************************************************
  45.  * TileStackWindows
  46.  *
  47.  * Calls theTileStackProc on a per-device basis to
  48.  * clean up (stack, tile or whatever else you can
  49.  * think of) all the windows on that device. Once
  50.  * all devices have been taken care of the part of
  51.  * the screen that needs to be updated is updated.
  52.  ****************************************************/
  53. void TileStackWindows(TileStackWindowsProc
  54.     theTileStackProc)
  55. {
  56.     WindowElementPtr    p, dp;
  57.     WindowPeek            w;
  58.     GDHandle            deviceHndl;
  59.     RgnHandle             sumOfStructRgns;
  60.     WindowElement        theWindows[MAX_WINDOWS],
  61.                         theDeviceWindows[MAX_WINDOWS];
  62.     long                theQDVers;
  63.     Rect                enclosingRect;
  64.     int                    i, totalWindows,
  65.                         windowsToClean,
  66.                         deviceWindows;
  67.     Boolean                needToRedraw, hasColorQD;
  68.     
  69.     /* check for color QuickDraw */
  70.     hasColorQD = FALSE;
  71.     if (TrapIsAvailable(_Gestalt)) {
  72.         Gestalt(gestaltQuickdrawVersion, &theQDVers);
  73.         hasColorQD = theQDVers >= 0x0100;
  74.     }
  75.  
  76.     sumOfStructRgns = NewRgn();
  77.     needToRedraw = FALSE;
  78.     
  79.     /* find the dominant device for each window
  80.      * as we add it to our list of windows
  81.      */
  82.     p = theWindows;
  83.     totalWindows = 0;
  84.     w = (WindowPeek) FrontWindow();
  85.     while (w != NIL && totalWindows < MAX_WINDOWS) {
  86.         p->theWindowPtr = w;
  87.         p->theDevHndl = NIL;
  88.         if (hasColorQD)
  89.             p->theDevHndl =
  90.               DominantDevice(&(*w->strucRgn)->rgnBBox);
  91.         p++;
  92.         totalWindows++;
  93.         /* or the old struct region into the
  94.          * update region
  95.          */
  96.         UnionRgn(sumOfStructRgns, w->strucRgn,
  97.             sumOfStructRgns);
  98.         w = w->nextWindow;
  99.     }
  100.     
  101.     if (totalWindows == 0)
  102.         goto Exit;
  103.     
  104.     /* set up enclosingRect here in case we don't
  105.      * have color QD; if we do have colorQD then
  106.      * enclosingRect is set again in the loop below
  107.      * on a per-device basis
  108.      */
  109.     enclosingRect = (*GetGrayRgn())->rgnBBox;
  110.     enclosingRect.top += TOPLEFT_SLOP;
  111.     enclosingRect.left += TOPLEFT_SLOP;
  112.     enclosingRect.bottom -= BOTRIGHT_SLOP;
  113.     enclosingRect.right -= BOTRIGHT_SLOP;
  114.  
  115.     windowsToClean = totalWindows;
  116.     do {
  117.         /* find the first device in the list that we
  118.          * haven't already done and copy all elements
  119.          * from that device into a new list
  120.          */
  121.         p = theWindows;
  122.         dp = theDeviceWindows;
  123.         deviceWindows = 0;
  124.         deviceHndl = BAD_DEVICE;
  125.         i = totalWindows;
  126.         do {
  127.             if (p->theDevHndl != BAD_DEVICE) {
  128.                 if (deviceHndl == BAD_DEVICE) {
  129.                     /* this is the first time we've
  130.                      * seen this device so we do a
  131.                      * little set up first
  132.                      */
  133.                     deviceHndl = p->theDevHndl;
  134.                     /* if we have colorQD, use the
  135.                      * device's rect
  136.                      */
  137.                     if (deviceHndl != NIL) {
  138.                         enclosingRect = (*deviceHndl)->gdRect;
  139.                         enclosingRect.top += TOPLEFT_SLOP;
  140.                         enclosingRect.left += TOPLEFT_SLOP;
  141.                         enclosingRect.bottom -= BOTRIGHT_SLOP;
  142.                         enclosingRect.right -= BOTRIGHT_SLOP;
  143.                         if (deviceHndl == GetMainDevice())
  144.                             enclosingRect.top += GetMBarHeight();
  145.                     }
  146.                 }
  147.                 if (deviceHndl == p->theDevHndl) {
  148.                     /* it's on the current device,
  149.                      * add it to the list
  150.                      */
  151.                     *dp++ = *p;
  152.                     deviceWindows++;
  153.                     /* we don't want to see this
  154.                      * one again
  155.                      */
  156.                     p->theDevHndl = BAD_DEVICE;
  157.                 }
  158.             }
  159.             p++;
  160.         } while (--i);
  161.         
  162.         if (deviceWindows > 0) {
  163.             /* do something to the windows on
  164.              * this device
  165.              */
  166.             needToRedraw |= (*theTileStackProc)
  167.               (&enclosingRect, theDeviceWindows,
  168.               deviceWindows);
  169.             windowsToClean -= deviceWindows;
  170.         }
  171.         
  172.     } while (windowsToClean > 0);
  173.     
  174.     if (needToRedraw) {
  175.     
  176.         /* add all of the new struct regions to the
  177.          * update region
  178.          */
  179.         p = theWindows;
  180.         do {
  181.             UnionRgn(sumOfStructRgns,
  182.               p->theWindowPtr->strucRgn,
  183.               sumOfStructRgns);
  184.             p++;
  185.         } while (--totalWindows);
  186.                 
  187.         /* To see a cool effect, trap on the next
  188.          * instruction and watch the screen as you
  189.          * step over it. All window frames are drawn
  190.          * with this one call to the ROMs.
  191.          */
  192.         PaintBehind(theWindows[0].theWindowPtr,
  193.           sumOfStructRgns);
  194.         
  195.         /* Need to reset the visRgns since
  196.          * MySizeWindow nuked 'em.
  197.          */
  198.         CalcVisBehind(theWindows[0].theWindowPtr,
  199.           sumOfStructRgns);
  200.     }
  201.  
  202. Exit:
  203.  
  204.     DisposeRgn(sumOfStructRgns);
  205. }
  206.  
  207.  
  208. /*****************************************************
  209.  * DominantDevice
  210.  *
  211.  * This returns a device hndl to the device that
  212.  * owns most of the given Rect (which is in global
  213.  * coordinates). This routine requires ColorQD.
  214.  ****************************************************/
  215. static GDHandle DominantDevice(Rect *theRect)
  216. {
  217.     GDHandle    nthDevice, theDevice;
  218.     long        greatestArea, sectArea;
  219.     Rect        theSect;
  220.     
  221.     nthDevice = theDevice = GetDeviceList();
  222.     greatestArea = 0;
  223.     do {
  224.         if (TestDeviceAttribute(nthDevice, screenDevice) &&
  225.           TestDeviceAttribute(nthDevice, screenActive)) {
  226.             SectRect(theRect, &(*nthDevice)->gdRect,
  227.               &theSect);
  228.             sectArea =
  229.               ((long) (theSect.bottom - theSect.top)) *
  230.               ((long) (theSect.right - theSect.left));
  231.             if (sectArea > greatestArea) {
  232.                 greatestArea = sectArea;
  233.                 theDevice = nthDevice;
  234.             }
  235.         }
  236.         nthDevice = GetNextDevice(nthDevice);
  237.     } while (nthDevice != NIL);
  238.     
  239.     return (theDevice);
  240. }
  241.  
  242.  
  243. /*****************************************************
  244.  * MyMoveWindow
  245.  *
  246.  * Quickly move the window. No screen updating
  247.  * will take place.
  248.  ****************************************************/
  249. Boolean MyMoveWindow(WindowPtr w, int leftGlobal,
  250.     int topGlobal, Boolean sizeChanged)
  251. {
  252.     Handle            theDefProc;
  253.     GrafPtr            oldPort;
  254.     Point            upperLeft;
  255.     char            oldState;
  256.     Boolean            itMoved;
  257.     
  258.     itMoved = FALSE;
  259.  
  260.     oldPort = thePort;
  261.     SetPort(w);
  262.     
  263.     /* Don't move it if it's already there, unless
  264.      * it was just resized (in which case we don't
  265.      * really need to call MovePortTo but we do
  266.      * need to call the windowDefProc below to fix
  267.      * up the regions).
  268.      */
  269.     if (!sizeChanged) {
  270.         upperLeft = topLeft(w->portRect);
  271.         LocalToGlobal(&upperLeft);
  272.         if (upperLeft.h == leftGlobal &&
  273.           upperLeft.v == topGlobal)
  274.             goto Exit;
  275.     }
  276.     
  277.     itMoved = TRUE;
  278.     
  279.     MovePortTo(leftGlobal, topGlobal);
  280.     
  281.     theDefProc = ((WindowPeek) w)->windowDefProc;
  282.     oldState = HGetState(theDefProc);
  283.     HLock(theDefProc);
  284.     
  285.     /* call the WDEF to update the regions */
  286.     (*(WDefProcHndl) theDefProc)(zoomDocProc, w,
  287.       wCalcRgns, 0);
  288.  
  289.     HSetState(theDefProc, oldState);
  290.  
  291. Exit:
  292.  
  293.     SetPort(oldPort);
  294.     
  295.     return (itMoved);
  296. }
  297.  
  298.  
  299. /*****************************************************
  300.  * MySizeWindow
  301.  *
  302.  * Quickly set the size of a window. Set the
  303.  * visRgn to NIL so that no screen updating takes
  304.  * place. The visRgn will be reset when we call
  305.  * CalcVisBehind later.
  306.  ****************************************************/
  307. Boolean MySizeWindow(WindowPtr w, int width,
  308.     int height)
  309. {
  310.     GrafPtr            oldPort;
  311.     
  312.     /* don't size it if it's already the right size */
  313.     if (w->portRect.right - w->portRect.left == width &&
  314.       w->portRect.bottom - w->portRect.top == height)
  315.           return(FALSE);
  316.           
  317.     oldPort = thePort;
  318.     SetPort(w);
  319.     
  320.     PortSize(width, height);
  321.     
  322.     /* nuke the visRgn so that moving this port
  323.      * (in MyMoveWindow) won't cause any screen
  324.      * drawing
  325.      */
  326.     SetEmptyRgn(((GrafPtr) w)->visRgn);
  327.     
  328.     SetPort(oldPort);
  329.     
  330.     return(TRUE);
  331. }
  332.